--------------------------------------------------------------------------------
--                                FPSqrt_BF16
--                                (FPSqrt_8_7)
-- This operator is part of the Infinite Virtual Library FloPoCoLib
-- All rights reserved 
-- Authors: 
--------------------------------------------------------------------------------
-- Pipeline depth: 9 cycles

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
library std;
use std.textio.all;
library work;

entity FPSqrt_BF16 is
   port ( clk, rst, ce : in std_logic;
          X : in  std_logic_vector(8+7+2 downto 0);
          R : out  std_logic_vector(8+7+2 downto 0)   );
end entity;

architecture arch of FPSqrt_BF16 is
signal fracX :  std_logic_vector(6 downto 0);
signal eRn0 :  std_logic_vector(7 downto 0);
signal xsX, xsX_d1, xsX_d2, xsX_d3, xsX_d4, xsX_d5, xsX_d6, xsX_d7, xsX_d8, xsX_d9 :  std_logic_vector(2 downto 0);
signal eRn1, eRn1_d1, eRn1_d2, eRn1_d3, eRn1_d4, eRn1_d5, eRn1_d6, eRn1_d7, eRn1_d8, eRn1_d9 :  std_logic_vector(7 downto 0);
signal w10 :  std_logic_vector(10 downto 0);
signal d9 :  std_logic;
signal x9 :  std_logic_vector(11 downto 0);
signal ds9 :  std_logic_vector(3 downto 0);
signal xh9 :  std_logic_vector(3 downto 0);
signal wh9 :  std_logic_vector(3 downto 0);
signal w9 :  std_logic_vector(10 downto 0);
signal s9 :  std_logic_vector(0 downto 0);
signal d8 :  std_logic;
signal x8 :  std_logic_vector(11 downto 0);
signal ds8 :  std_logic_vector(4 downto 0);
signal xh8 :  std_logic_vector(4 downto 0);
signal wh8 :  std_logic_vector(4 downto 0);
signal w8, w8_d1 :  std_logic_vector(10 downto 0);
signal s8, s8_d1 :  std_logic_vector(1 downto 0);
signal d7 :  std_logic;
signal x7 :  std_logic_vector(11 downto 0);
signal ds7 :  std_logic_vector(5 downto 0);
signal xh7 :  std_logic_vector(5 downto 0);
signal wh7 :  std_logic_vector(5 downto 0);
signal w7, w7_d1 :  std_logic_vector(10 downto 0);
signal s7, s7_d1 :  std_logic_vector(2 downto 0);
signal d6 :  std_logic;
signal x6 :  std_logic_vector(11 downto 0);
signal ds6 :  std_logic_vector(6 downto 0);
signal xh6 :  std_logic_vector(6 downto 0);
signal wh6 :  std_logic_vector(6 downto 0);
signal w6, w6_d1 :  std_logic_vector(10 downto 0);
signal s6, s6_d1 :  std_logic_vector(3 downto 0);
signal d5 :  std_logic;
signal x5 :  std_logic_vector(11 downto 0);
signal ds5 :  std_logic_vector(7 downto 0);
signal xh5 :  std_logic_vector(7 downto 0);
signal wh5 :  std_logic_vector(7 downto 0);
signal w5, w5_d1 :  std_logic_vector(10 downto 0);
signal s5, s5_d1 :  std_logic_vector(4 downto 0);
signal d4 :  std_logic;
signal x4 :  std_logic_vector(11 downto 0);
signal ds4 :  std_logic_vector(8 downto 0);
signal xh4 :  std_logic_vector(8 downto 0);
signal wh4 :  std_logic_vector(8 downto 0);
signal w4, w4_d1 :  std_logic_vector(10 downto 0);
signal s4, s4_d1 :  std_logic_vector(5 downto 0);
signal d3 :  std_logic;
signal x3 :  std_logic_vector(11 downto 0);
signal ds3 :  std_logic_vector(9 downto 0);
signal xh3 :  std_logic_vector(9 downto 0);
signal wh3 :  std_logic_vector(9 downto 0);
signal w3, w3_d1 :  std_logic_vector(10 downto 0);
signal s3, s3_d1 :  std_logic_vector(6 downto 0);
signal d2 :  std_logic;
signal x2 :  std_logic_vector(11 downto 0);
signal ds2 :  std_logic_vector(10 downto 0);
signal xh2 :  std_logic_vector(10 downto 0);
signal wh2 :  std_logic_vector(10 downto 0);
signal w2, w2_d1 :  std_logic_vector(10 downto 0);
signal s2, s2_d1 :  std_logic_vector(7 downto 0);
signal d1 :  std_logic;
signal x1 :  std_logic_vector(11 downto 0);
signal ds1 :  std_logic_vector(11 downto 0);
signal xh1 :  std_logic_vector(11 downto 0);
signal wh1 :  std_logic_vector(11 downto 0);
signal w1, w1_d1 :  std_logic_vector(10 downto 0);
signal s1, s1_d1 :  std_logic_vector(8 downto 0);
signal d0 :  std_logic;
signal fR :  std_logic_vector(10 downto 0);
signal fRn1, fRn1_d1 :  std_logic_vector(8 downto 0);
signal round, round_d1 :  std_logic;
signal fRn2 :  std_logic_vector(6 downto 0);
signal Rn2 :  std_logic_vector(14 downto 0);
signal xsR :  std_logic_vector(2 downto 0);
begin
   process(clk)
      begin
         if clk'event and clk = '1' then
            if ce = '1' then
               xsX_d1 <=  xsX;
               xsX_d2 <=  xsX_d1;
               xsX_d3 <=  xsX_d2;
               xsX_d4 <=  xsX_d3;
               xsX_d5 <=  xsX_d4;
               xsX_d6 <=  xsX_d5;
               xsX_d7 <=  xsX_d6;
               xsX_d8 <=  xsX_d7;
               xsX_d9 <=  xsX_d8;
               eRn1_d1 <=  eRn1;
               eRn1_d2 <=  eRn1_d1;
               eRn1_d3 <=  eRn1_d2;
               eRn1_d4 <=  eRn1_d3;
               eRn1_d5 <=  eRn1_d4;
               eRn1_d6 <=  eRn1_d5;
               eRn1_d7 <=  eRn1_d6;
               eRn1_d8 <=  eRn1_d7;
               eRn1_d9 <=  eRn1_d8;
               w8_d1 <=  w8;
               s8_d1 <=  s8;
               w7_d1 <=  w7;
               s7_d1 <=  s7;
               w6_d1 <=  w6;
               s6_d1 <=  s6;
               w5_d1 <=  w5;
               s5_d1 <=  s5;
               w4_d1 <=  w4;
               s4_d1 <=  s4;
               w3_d1 <=  w3;
               s3_d1 <=  s3;
               w2_d1 <=  w2;
               s2_d1 <=  s2;
               w1_d1 <=  w1;
               s1_d1 <=  s1;
               fRn1_d1 <=  fRn1;
               round_d1 <=  round;
            end if;
         end if;
      end process;
   fracX <= X(6 downto 0); -- fraction
   eRn0 <= "0" & X(14 downto 8); -- exponent
   xsX <= X(17 downto 15); -- exception and sign
   eRn1 <= eRn0 + ("00" & (5 downto 0 => '1')) + X(7);
   w10 <= "111" & fracX & "0" when X(7) = '0' else
          "1101" & fracX;
   -- Step 9
   d9 <= w10(10);
   x9 <= w10 & "0";
   ds9 <=  "0" &  (not d9) & d9 & "1";
   xh9 <= x9(11 downto 8);
   with d9 select
      wh9 <= xh9 - ds9 when '0',
            xh9 + ds9 when others;
   w9 <= wh9(2 downto 0) & x9(7 downto 0);
   s9 <= "" & (not d9) ;
   -- Step 8
   d8 <= w9(10);
   x8 <= w9 & "0";
   ds8 <=  "0" & s9 &  (not d8) & d8 & "1";
   xh8 <= x8(11 downto 7);
   with d8 select
      wh8 <= xh8 - ds8 when '0',
            xh8 + ds8 when others;
   w8 <= wh8(3 downto 0) & x8(6 downto 0);
   s8 <= s9 & not d8;
   ----------------Synchro barrier, entering cycle 1----------------
   -- Step 7
   d7 <= w8_d1(10);
   x7 <= w8_d1 & "0";
   ds7 <=  "0" & s8_d1 &  (not d7) & d7 & "1";
   xh7 <= x7(11 downto 6);
   with d7 select
      wh7 <= xh7 - ds7 when '0',
            xh7 + ds7 when others;
   w7 <= wh7(4 downto 0) & x7(5 downto 0);
   s7 <= s8_d1 & not d7;
   ----------------Synchro barrier, entering cycle 2----------------
   -- Step 6
   d6 <= w7_d1(10);
   x6 <= w7_d1 & "0";
   ds6 <=  "0" & s7_d1 &  (not d6) & d6 & "1";
   xh6 <= x6(11 downto 5);
   with d6 select
      wh6 <= xh6 - ds6 when '0',
            xh6 + ds6 when others;
   w6 <= wh6(5 downto 0) & x6(4 downto 0);
   s6 <= s7_d1 & not d6;
   ----------------Synchro barrier, entering cycle 3----------------
   -- Step 5
   d5 <= w6_d1(10);
   x5 <= w6_d1 & "0";
   ds5 <=  "0" & s6_d1 &  (not d5) & d5 & "1";
   xh5 <= x5(11 downto 4);
   with d5 select
      wh5 <= xh5 - ds5 when '0',
            xh5 + ds5 when others;
   w5 <= wh5(6 downto 0) & x5(3 downto 0);
   s5 <= s6_d1 & not d5;
   ----------------Synchro barrier, entering cycle 4----------------
   -- Step 4
   d4 <= w5_d1(10);
   x4 <= w5_d1 & "0";
   ds4 <=  "0" & s5_d1 &  (not d4) & d4 & "1";
   xh4 <= x4(11 downto 3);
   with d4 select
      wh4 <= xh4 - ds4 when '0',
            xh4 + ds4 when others;
   w4 <= wh4(7 downto 0) & x4(2 downto 0);
   s4 <= s5_d1 & not d4;
   ----------------Synchro barrier, entering cycle 5----------------
   -- Step 3
   d3 <= w4_d1(10);
   x3 <= w4_d1 & "0";
   ds3 <=  "0" & s4_d1 &  (not d3) & d3 & "1";
   xh3 <= x3(11 downto 2);
   with d3 select
      wh3 <= xh3 - ds3 when '0',
            xh3 + ds3 when others;
   w3 <= wh3(8 downto 0) & x3(1 downto 0);
   s3 <= s4_d1 & not d3;
   ----------------Synchro barrier, entering cycle 6----------------
   -- Step 2
   d2 <= w3_d1(10);
   x2 <= w3_d1 & "0";
   ds2 <=  "0" & s3_d1 &  (not d2) & d2 & "1";
   xh2 <= x2(11 downto 1);
   with d2 select
      wh2 <= xh2 - ds2 when '0',
            xh2 + ds2 when others;
   w2 <= wh2(9 downto 0) & x2(0 downto 0);
   s2 <= s3_d1 & not d2;
   ----------------Synchro barrier, entering cycle 7----------------
   -- Step 1
   d1 <= w2_d1(10);
   x1 <= w2_d1 & "0";
   ds1 <=  "0" & s2_d1 &  (not d1) & d1 & "1";
   xh1 <= x1(11 downto 0);
   with d1 select
      wh1 <= xh1 - ds1 when '0',
            xh1 + ds1 when others;
   w1 <= wh1(10 downto 0);
   s1 <= s2_d1 & not d1;
   ----------------Synchro barrier, entering cycle 8----------------
   d0 <= w1_d1(10) ;
   fR <= s1_d1 & not d0 & '1';
   -- normalisation of the result, removing leading 1
   with fR(10) select
      fRn1 <= fR(9 downto 2) & (fR(1) or fR(0)) when '1',
              fR(8 downto 0)                    when others;
   round <= fRn1(1) and (fRn1(2) or fRn1(0)) ; -- round  and (lsb or sticky) : that's RN, tie to even
   ----------------Synchro barrier, entering cycle 9----------------
   fRn2 <= fRn1_d1(8 downto 2) + ((6 downto 1 => '0') & round_d1); -- rounding sqrt never changes exponents 
   Rn2 <= eRn1_d9 & fRn2;
   -- sign and exception processing
   with xsX_d9 select
      xsR <= "010"  when "010",  -- normal case
             "100"  when "100",  -- +infty
             "000"  when "000",  -- +0
             "001"  when "001",  -- the infamous sqrt(-0)=-0
             "110"  when others; -- return NaN
   R <= xsR & Rn2; 
end architecture;

